﻿#region Using

using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using Commons.Extension;
using SAPbouiCOM;
using SapFramework.Interface.Events;

using Form = SapFramework.Interface.Controls.Forms.Base.Form;

#endregion

namespace SapFramework.Interface.Controls.Items.Base
{
    /// <summary>
    /// Realiza o encapsulamento de um objeto do tipo <see cref="SAPbouiCOM.Item"/> da UI API do SAP Business One.
    /// </summary>
    public abstract class Item : SAPbouiCOM.Item
    {
        #region Eventos

        /// <summary>
        /// Evento disparado quando o botão principal do mouse foi pressionado sobre um item, mas nenhuma ação foi tomada ainda.
        /// </summary>
        [Event( BoEventTypes.et_CLICK )]
        public event EventBoolItem OnBeforeClick;

        /// <summary>
        /// Evento disparado quando o botão principal do mouse foi pressionado sobre um item, e qualquer ação do SBO já foi realizada.
        /// </summary>
        [Event( BoEventTypes.et_CLICK )]
        public event EventVoidItem OnAfterClick;

        #endregion

        /// <summary>
        /// Guarda uma referencia para o formulário que é dono do item
        /// </summary>
        protected readonly Form mForm;

        /// <summary>
        /// Faz referencia a um objeto do tipo Item do SAP Business One.
        /// </summary>
        protected readonly SAPbouiCOM.Item mItem;

        /// <summary>
        /// Construtor
        /// </summary>
        /// <param name="aForm">O formulário ao qual o item pertence</param>
        /// <param name="aItemUniqueId">Id único do Item do Form do SAP Business One</param>
        /// <param name="aItemType">O tipo do Item para o SAP Business One</param>
        internal Item( Form aForm, string aItemUniqueId, BoFormItemTypes aItemType )
        {
            mForm = aForm;
            mItem = mForm.Items.Add( aItemUniqueId, this, aItemType );            
        }

        #region Implementation of IItem

        /// <summary>
        /// Cor em primeiro plano do Item
        /// </summary>
        public Color ForegroundColor
        {
            get { return ColorTranslator.FromWin32( mItem.ForeColor ); }
            set { mItem.ForeColor = ColorTranslator.ToWin32( value ); }
        }

        /// <summary>
        /// Cor em segundo plano do Item
        /// </summary>
        public Color BackgroundColor
        {
            get { return ColorTranslator.FromWin32( mItem.BackColor ); }
            set { mItem.BackColor = ColorTranslator.ToWin32( value ); }
        }

        /// <summary>
        /// Indica o estilo da fonte para a demonstração de texto pelo item
        /// </summary>
        public BoTextStyle[] TextStyles
        {
            get
            {
                return mItem.TextStyle.ToEnum<BoTextStyle>();                
            }
            set { mItem.TextStyle = value.ToBitwise(); }
        }

        /// <summary>
        /// Simula um click do usuário sobre o item específico.
        /// </summary>
        /// <param name="aClickType">Tipo do Click</param>
        /// <see cref="BoCellClickType"/>
        public void Click( BoCellClickType aClickType = BoCellClickType.ct_Regular )
        {
            mItem.Click( aClickType );
        }

        /// <summary>
        /// Recarrega o Item a partir da aplicação do SAP Business One.
        /// </summary>
        /// <remarks>
        /// Utilize este método para atualizar o componente com os valores da base de dados no formulário.
        /// </remarks>
        public void Refresh()
        {
            mItem.Refresh();
        }

        /// <summary>
        /// Atualiza a interface do item no formulário.
        /// </summary>
        /// <remarks>
        /// Utilize este método para atualizar um objeto a partir da base de dados.
        /// </remarks>
        public void Update()
        {
            mItem.Update();
        }

        /// <summary>
        /// Retorna o comportamento de um atributo do item para formulário com gerenciamento automático de Modos.
        /// </summary>
        /// <remarks>
        /// Pode-se setar o comportamento de um atributo do item utilizando a função <see cref="SetAutoManagedAttribute"/>.
        /// </remarks>
        /// <param name="aAttribute">Especifica o atributo do item para o qual deseja-se recuperar o comportamento</param>
        /// <param name="aFormMode">Especifica o modo do formulário</param>
        /// <returns></returns>
        public BoModeVisualBehavior GetAutoManagedAttribute( BoAutoManagedAttr aAttribute, BoAutoFormMode aFormMode )
        {
            return mItem.GetAutoManagedAttribute( aAttribute, aFormMode );
        }

        /// <summary>
        /// Seta o comportamento do item em questão, atualizando um de seus atributos, para quando um formulário automaticamente gerenciado trocar de modo.
        /// </summary>
        /// <remarks>
        /// Utilize este método para manipular o comportamento de itens em modos de formulário especificos, quando este for um formulário automaticamente gerenciado pelo SAP Business One.
        /// </remarks>
        /// <param name="aAttribute">Especifica o atributo do item para o qual deseja setar o comportamento. O comportamento deve ser especificado em <paramref name="aBehavior"/></param>
        /// <param name="aFormModes">Agrupe os modos de <see cref="BoAutoFormMode"/> de maneira Bitwise nesta variavel</param>
        /// <param name="aBehavior">Especifica um comportamento para o item em questão, para seu atributo escolhido em <paramref name="aAttribute"/>, quando o formulário estiver no modo informado em <paramref name="aBehavior"/></param>
        [Obsolete( "Utilizar versão com array", false )]
        void IItem.SetAutoManagedAttribute( BoAutoManagedAttr aAttribute, int aFormModes, BoModeVisualBehavior aBehavior )
        {
            mItem.SetAutoManagedAttribute( aAttribute, aFormModes, aBehavior );
        }

        /// <summary>
        /// Retorna os dados especificos do Item
        /// </summary>
        [Obsolete( "Existem classes especializadas que já convertem esta propriedade", false )]
        object IItem.Specific
        {
            get { return mItem.Specific; }
        }

        /// <summary>
        /// Posição referente ao eixo Y do item, relativa ao Client do SAP Business One.
        /// </summary>
        public int Top
        {
            get { return mItem.Top; }
            set { mItem.Top = value; }
        }

        /// <summary>
        /// Posição referente ao eixo X do item, relativa ao Client do SAP Business One.
        /// </summary>
        public int Left
        {
            get { return mItem.Left; }
            set { mItem.Left = value; }
        }

        /// <summary>
        /// Altura do item
        /// </summary>
        public int Height
        {
            get { return mItem.Height; }
            set { mItem.Height = value; }
        }

        /// <summary>
        /// Comprimento do item
        /// </summary>
        public int Width
        {
            get { return mItem.Height; }
            set { mItem.Height = value; }
        }

        /// <summary>
        /// Indica se o item está visivel.
        /// </summary>
        public bool Visible
        {
            get { return mItem.Visible; }
            set { mItem.Visible = value; }
        }

        /// <summary>
        /// Indica o limite inferior do nível de painéis do formulário no qual o item estará visivel. Por padrão é 0 (zero).
        /// Se o formulário tiver mais de um painel, você pode especificar o alcance de paineis no qual o campo estará visivel.
        /// </summary>
        /// <remarks>
        /// Funciona em conjunto com <see cref="ToPane"/>
        /// </remarks>
        public int FromPane
        {
            get { return mItem.FromPane; }
            set { mItem.FromPane = value; }
        }

        /// <summary>
        /// Indica o limite superior do nível de painéis do formulário no qual o item estará visivel. Por padrão é 0 (zero).
        /// Se o formulário tiver mais de um painel, você pode especificar o alcance de paineis no qual o campo estará visivel.
        /// </summary>
        /// <remarks>
        /// Funciona em conjunto com <see cref="FromPane"/>
        /// </remarks>
        public int ToPane
        {
            get { return mItem.ToPane; }
            set { mItem.ToPane = value; }
        }

        /// <summary>
        /// Indica quando deve mostrar o valor ou a descrição do <see cref="ValidValue"/>
        /// </summary>
        /// <remarks>
        /// //ToDo Testar se é verdadeiro esta afirmação.
        /// Valido apenas para componentes que possuem <see cref="ValidValues"/>, em especial,do tipo <see cref="ComboBox"/>
        /// </remarks>
        /// <value>
        /// <c>true</c>: Mostra a descrição do <see cref="ValidValue"/>
        /// <c>false</c>: Mostra o valor do <see cref="ValidValue"/>
        /// </value>
        public bool DisplayDesc
        {
            get { return mItem.DisplayDesc; }
            set { mItem.DisplayDesc = value; }
        }

        /// <summary>
        /// Informa a descrição do componente que irá aparecer na barra de status do SAP Business One.
        /// </summary>
        public string Description
        {
            get { return mItem.Description; }
            set { mItem.Description = value; }
        }

        /// <summary>
        /// Informa se o texto do componente deve estar alinha a direita ou a esquerda.
        /// </summary>
        public bool RightJustified
        {
            get { return mItem.RightJustified; }
            set { mItem.RightJustified = value; }
        }

        /// <summary>
        /// Indica quando este item está ativo.
        /// </summary>
        /// <remarks>
        /// Itens do SAP Business One não podem ser ativados via UI API.
        /// </remarks>
        /// <remarks>
        /// Caso o item esteja sendo focado pelo formulário, este não poderá ser desativado.
        /// </remarks>
        public bool Enabled
        {
            get { return mItem.Enabled; }
            set
            {
                Debug.Assert( !value && mForm.ActiveItem == mItem.UniqueID,
                              string.Format( "O componente {0}[{1}].{2} não pode ser desativado enquanto estiver em foco", mForm.TypeEx, mForm.UniqueID, UniqueID ) );

                Debug.Assert( value && mForm.IsSystem,
                              string.Format( "Componentes nativos do SAP Business One não podem ser ativados via UI API, no item {0}[{1}].{2}", mForm.TypeEx, mForm.UniqueID, UniqueID ) );

                mItem.Enabled = value;
            }
        }

        /// <summary>
        /// Retorna o tipo do item.
        /// </summary>
        /// <remarks>
        /// Classes que especializam a classe <see cref="SAPbouiCOM.Item"/>, com a <see cref="SAPbouiCOM.Button"/>, possuem sua própria implementação 
        /// de <see cref="SAPbouiCOM.Item.Type"/>, por isto, para chamar a interface <see cref="SAPbouiCOM.Item.Type"/> faça primeiro um cast do objeto 
        /// para <see cref="SAPbouiCOM.Item"/>
        /// <example>
        /// Button mBtnOk = new Button( lForm, "1" );
        /// ((SAPbouiCOM.Item)mBtnOk).Type = BoFormItemTypes.it_BUTTON;
        /// </example>
        /// </remarks>
        BoFormItemTypes IItem.Type
        {
            get { return mItem.Type; }
        }

        /// <summary>
        /// Retorna o código único deste item para o formulário.
        /// </summary>
        public string UniqueID
        {
            get { return mItem.UniqueID; }
        }

        /// <summary>
        /// Permite uma ligação a outro objeto do SAP Business One pelo seu <see cref="UniqueID"/>
        /// </summary>
        public string LinkTo
        {
            get { return mItem.LinkTo; }
            set
            {
                Debug.Assert( value != mItem.UniqueID, "O item {0}[{1}].{2} não pode ser ligado a ele mesmo", mForm.TypeEx, mForm.UniqueID, UniqueID );
                mItem.LinkTo = value;
            }
        }

        /// <summary>
        /// Indica se este item ativa uma mudança no modo do formulário.
        /// </summary>
        public bool AffectsFormMode
        {
            get { return mItem.AffectsFormMode; }
            set { mItem.AffectsFormMode = value; }
        }

        /// <summary>
        /// Cor em primeiro plano do Item
        /// </summary>
        [Obsolete( "Utilize a propriedade ForegroundColor", true )]
        public int ForeColor
        {
            get { return mItem.ForeColor; }
            set { mItem.ForeColor = value; }
        }

        /// <summary>
        /// Cor em segundo plano do Item
        /// </summary>
        [Obsolete( "Utilize a propriedade BackgroundColor", true )]
        public int BackColor
        {
            get { return mItem.BackColor; }
            set { mItem.BackColor = value; }
        }

        /// <summary>
        /// Indica o estilo da fonte para a demonstração de texto pelo item
        /// </summary>
        [Obsolete( "Utilize a propriedade TextStyles", true )]
        public int TextStyle
        {
            get { return mItem.TextStyle; }
            set { mItem.TextStyle = value; }
        }

        /// <summary>
        /// Tamanho da fonte to texto
        /// </summary>
        public int FontSize
        {
            get { return mItem.FontSize; }
            set { mItem.FontSize = value; }
        }

        /// <summary>
        /// Seta o comportamento do item em questão, atualizando um de seus atributos, para quando um formulário automaticamente gerenciado trocar de modo.
        /// </summary>
        /// <remarks>
        /// Utilize este método para manipular o comportamento de itens em modos de formulário especificos, quando este for um formulário automaticamente gerenciado pelo SAP Business One.
        /// </remarks>
        /// <param name="aAttribute">Especifica o atributo do item para o qual deseja setar o comportamento. O comportamento deve ser especificado em <paramref name="aBehavior"/></param>
        /// <param name="aFormModes">Um array contendo os modos do formulário em que o comportamento será válido. Se for nulo, então <paramref name="aFormModes"/> valerá <see cref="BoAutoFormMode.afm_All"/></param>
        /// <param name="aBehavior">Especifica um comportamento para o item em questão, para seu atributo escolhido em <paramref name="aAttribute"/>, quando o formulário estiver no modo informado em <paramref name="aBehavior"/></param>
        public void SetAutoManagedAttribute( BoAutoManagedAttr aAttribute, BoModeVisualBehavior aBehavior, BoAutoFormMode[] aFormModes = null )
        {
            int lModesMask = 0;

            if ( aFormModes == null || aFormModes.Length == 0 || aFormModes.Contains( BoAutoFormMode.afm_All ) )
            {
                lModesMask = (int) BoAutoFormMode.afm_All;
            }
            else
            {
                Array.ForEach( aFormModes, aValue => lModesMask |= (int) aValue );
            }

            mItem.SetAutoManagedAttribute( aAttribute, lModesMask, aBehavior );
        }

        #endregion
    }
}